#!/usr/bin/ksh

#########################################################################
#									#
# Name:		mkpkg.slackpkg (Shell script)				#
#									#
# Completed:	12th August, 2005.					#
#									#
# Updated:	27th September, 2005.					#
#									#
# Author:	Simon Edwards, linuxha.net				#
#									#
# Arguments:	-V		Print codemgr packaging type - 		#
#				currently set to 1.			#
#									#
# Arguments:	-r rel [-x cfg] [-v] [-f]				#
#		-r		Indicate the number of the release to	#
#				create - assigned by the 		#
#				mkpkg wrapper script usually.		#
#		-x		Specify an alternative cfg file - 	#
#				the default will be "cfg".		#
#		-f		Force create - if a version of this	#
#				release already exists it should be	#
#				over-written.				#
#									#
# Purpose:	This creates takes the information for the current	#
#		project and creates a slackware package for it. It does	#
#		this using the information taken from the RELMGR_CONF	#
#		file and also the configuration file used for packing	#
#		itself - found typically in the pkg/cfg file.		#
#									#
#		This script does not check that all source code is	#
#		checked it - that is the business of the mkpkg wrapper	#
#		script.							#
#									#
#		A slackaware package is a gzipped-tar file that		#
#		has all files stored in relative positions to the	#
#		absolute install path - for example usr/bin/file	#
#		to install usr/bin/file.				#
#									#
#		A slackware package also has a install directory	#
#		with at least a slack-desc file in it, which has the	#
#		11 lines beginning with package:<sp> (where <sp> is	#
#		a space).						#
#									#
#		Optionally this directory can contain a file called	#
#		doinst.sh - which is a post installation shell 		#
#		script.							#
#									#
#		And that is it! Simplest format known to Linux?		#
#									#
#		Packages have the naming scheme of:			#
#		name-version-architecture-revision.tgz			#
#									#
#		For codemgr, the architecture will be hardcoded		#
#		to i486 since slackware is only x86 at present.		#
#									#
# Limitations:	1 - Limited package manager.				#
#									#
# Environment:	RELMGR_CFG	- Defines the file name containing the	#
#				  configuration settings for the 	#
#				  release manager for this user.	#
#									#
# Exit Codes:	0  - Package created successfully / all files in 	#
#		     version control system.				#
#		>1 - An error has occurred / not all files under 	#
#		     version control are checked back in.		#
# 									#
# Version:	@(#)1.1 Original (SE)>					#
#									#
#########################################################################

function logmsg
{
	[[ $ARG_verbose -eq 0 ]] && return
	print "MSG  : $1"
}

function logwarn
{
	print "WARN : $1"
}

function logerr
{
	print -u2 "ERROR: $1"
	[[ -n "$2" ]] && exit $2
}

SCRIPT=$(basename $0)
function loadvar 
{
	#################################################################
	# If we do not currently have a pkg directory, then create one!	#
	#################################################################

	[[ ! -d $1/pkg ]] && {
		mkdir -p $1/pkg 2>/dev/null || {
			logerr "Unable to create pkg directory" 2;
		}
		logwarn "Pkg directory auto-created!";
	}

	[[ ! -f $1/pkg/$CFGFILE ]] && {
		logerr "Configuration file \"$1/pkg/$CFGFILE\" does not exist." 5;
	}
	if [[ -n "$3" && "$3" = m ]]
	then
		( . $1/pkg/$CFGFILE 2>/dev/null; eval print \$$2 )
	elif [[ -n "$3" && "$3" = s ]]
	then
		awk -v searchfor="$2" '$1 == "#" {next} $1 ~ searchfor {split($0,a,"="); if(substr(a[1],1,length(searchfor)) == searchfor) { printf("%s %s\n",a[1],a[2]);exit(0);}}' \
		$1/pkg/$CFGFILE
	else
		awk -v searchfor="$2" '$1 == "#" {next} $1 ~ searchfor {split($0,a,"="); if(substr(a[1],1,length(searchfor)) == searchfor) { printf("%s %s\n",a[1],a[2]);}}' \
		$1/pkg/$CFGFILE
	fi
	return 0
}

function usage
{
	print -u2 "Usage: $SCRIPT -r release [-f] [-v]

Written by Simon Edwards 2005 , linuxha.net
Please see the codemgr_$SCRIPT(1) manual page for more details.
"
exit 1
}

[[ -z "$RELMGR_CFG" ]] && {
	logerr "Variable \"RELMGR_CFG\" is not defined." 10;
}

[[ ! -f "$RELMGR_CFG" ]] && {
	logerr "\"RELMGR_CFG\" setting ($RELMGR_CFG) is not valid." 11;
}

whoami=$(whoami)

#########################################################################
# Now source the configuration information...				#
#########################################################################

. $RELMGR_CFG

export PROJECT_PREFIX PROJECT_PKGDIR PROJECT_RELDB PKG_TYPE VCTYPE
export DEFAULT_GROUP DEFAULT_PERMS DEFAULT_OWNER IGNORE_SUFFIXES
export FINAL_DEPOT
#########################################################################
# If the wrapper has been to generate the package it will have set the	#
# BUILD_IN_TMP variable, which now becomes the PROJECT_PREFIX for this	#
# particular package build.						#
#########################################################################

if [[ -n "$BUILD_IN_TMP" && -d $BUILD_IN_TMP ]]
then
	logmsg "PROJECT_PREFIX modified to $BUILD_IN_TMP"
	PROJECT_PREFIX=$BUILD_IN_TMP
fi

#########################################################################
# Now we have the basic details we need to parse the command line	#
# arguments to ensure everything looks ok.				#
#########################################################################

VERSION=0
FORCE=0
RELEASE=""
ARG_verbose=0
CFGFILE=""

while getopts ":Vfvr:x:" argval
do
	case $argval in
		V)	VERSION=1		;;
		f)	FORCE=1			;;
		v)	ARG_verbose=1		;;
		x)	CFGFILE=$OPTARG		;;
		r)	RELEASE=$OPTARG		;;
		*)	usage
	esac
done

if [[ $VERSION = 1 ]]
then
	print 1
	exit 0
fi

[[ -z "$CFGFILE" ]] && CFGFILE=cfg
[[ -z "$RELEASE" ]] && usage

#########################################################################
# We now work out the current product name, using the current directory	#
# path as a starting point. If the current directory path is not	#
# path of the PROJECT_PREFIX then we need to raise an error.		#
#########################################################################

project_name=$(print $PWD|
	awk -v projs=$PROJECT_PREFIX '{if(substr($1,1,length(projs))!=projs) exit(0);
		split(substr($1,2+length(projs)),a,"/");
		print a[1];}')

if [[ -z "$project_name" ]]
then
	logerr "Current path is invalid for a project!"
	logerr "Path must be sub-directory of \"$PROJECT_PREFIX\"." 12
fi

logmsg "Project name ascertained to be: $project_name"
pkg_name=$(loadvar $PROJECT_PREFIX/$project_name NAME|awk '{print $2}')

if [[ -n "$pkg_name" && "$CFGFILE" != cfg ]]
then
	logmsg "Building package: $pkg_name"
else
	pkg_name=$project_name
fi

pkgfile_name="$pkg_name-$RELEASE-i486-1.tgz"
logmsg "Project source tree named as: $project_name"

#########################################################################
# Load in details we need - we cobble enough for a slack-desc file...	#
#########################################################################

pkg_depot=$(loadvar $PROJECT_PREFIX/$project_name DEPOT.SLACKPKG|awk '{print $2}')
[[ -z "$pkg_depot" ]] &&
	pkg_depot=$(loadvar $PROJECT_PREFIX/$project_name DEPOT|awk '{print $2}')

pkg_desc=$(loadvar $PROJECT_PREFIX/$project_name DESCRIPTION|awk '{for(n=2; n<=NF; n++) printf("%s ",$n);}')
pkg_license=$(loadvar $PROJECT_PREFIX/$project_name LICENSE s|awk '{for(n=2; n<=NF; n++) printf("%s ",$n);}')
pkg_ignore_suffixes=$(loadvar $PROJECT_PREFIX/$project_name IGNORE_SUFFIXES s|awk '{print $2}' | sed 's/"//g')

if [[ -z "$pkg_ignore_suffixes" && -n "$IGNORE_SUFFIXES" ]]
then
	pkg_ignore_suffixes="$IGNORE_SUFFIXES"
	logmsg "Ignored suffixes for packaging: $pkg_ignore_suffixes"
fi

[[ -z "$pkg_name" ]] &&
	pkg_name="$project_name" &&
	logwarn "Defaulting package name to $pkg_name"

[[ -z "$pkg_depot" ]] && {
	[[ -n "$BUILD_DEPOT" ]] && pkg_depot="$BUILD_DEPOT" ||
		pkg_depot="$HOME/slackpkg_depot";
	logwarn "Defaulting package build depot to $pkg_depot";
}

[[ -z "$pkg_desc" ]] &&
	pkg_desc="Default short description for $pkg_name" &&
	logwarn "Defaulting short package description"

[[ -z "$pkg_ldesc" ]] &&
	pkg_ldesc="Default long description for $pkg_name" &&
	logwarn "Defaulting long package description"

[[ -z "$pkg_license" ]] &&
	pkg_license="GPL" &&
	logwarn "Defaulting license to $pkg_license"

#########################################################################
# Create the depot directory if it does not yet exist.			#
#########################################################################

[[ ! -d "$pkg_depot" ]] && {
	mkdir -p $pkg_depot 2>/dev/null || {
		logerr "Unable to create package depot $pkg_depot" 14;
	} ; 
	logmsg "Created Package depot: $pkg_depot";
}

slack_desc="$pkg_name: $pkg_desc\n$pkg_name: \n"
slack_desc="${slack_desc}$pkg_name: License: $pkg_license\n$pkg_name: \n"

#########################################################################
# 7 lines maximum to add from long desc..., padding with blank		#
# lines if necessary.							#
#########################################################################

line=1
print "$pkg_ldesc" | while read cline
do
	slack_desc="${slack_desc}$pkg_name: $cline\n"
	let line=line+1
	((line>7)) && break
done

while ((line<7))
do
	slack_desc="${slack_desc}$pkg_name: \n"
	let line=line+1
done

#########################################################################
# At this time it is now possible to get details of all the files	#
# to copy to the package area, creating another temporary directory	#
# first.								#
#########################################################################

mkdir /tmp/slackpkg-$$ || logerr "Unable to create directory." 18;
oodir="/tmp/slackpkg-$$"

#########################################################################
# Now the interesting bit...						#
# We get all DIR:... variables and build the fileset using this		#
# information.								#
#########################################################################

predir=""
predestdir=""
permsfile="/tmp/slackpkg-$$-perms"

loadvar $PROJECT_PREFIX/$project_name DIR: |
while read dir dest
do
        dir=$(print $dir|awk -v FS=: '{print $2}')
	[[ -f  $PROJECT_PREFIX/$project_name/$dir/.ignore ]] && {
		logmsg "Ignoring directory $dir";
		continue;
	}

	#################################################################
	# Get the user, group and permissions, if specified		#
	#################################################################

	user=$(print $dest|awk -v FS=, '{print $2}')
	user=${user:-root}
	group=$(print $dest|awk -v FS=, '{print $3}')
	group=${group:-root}
	perms=$(print $dest|awk -v FS=, '{print $4}')
	perms=${perms:-755}
	destdir=$(print $dest|awk -v FS=, '{print $1}')

	#################################################################
	# Now check if extended DIR:ddd(file)... syntax has been	#
	# used...							#
	#################################################################

	pickfiles=$(print $dir|
		awk '{s1=index($0,"("); s2=index($0,")");
			if(s1>0 && s2>0) {
				print substr($0,s1+1,s2-s1-1);
			}
		     }')

	[[ -z "$pickfiles" ]] && pattern="*"
	[[ -n "$pickfiles" ]] && pattern=$(print "$pickfiles" | tr ',' ' ')
	logmsg "Packaging directory $dir => $destdir"
	mycd=$PWD

	#################################################################
	# Chop of the filtered files bit from the directory name	#
	# if required.							#
	#################################################################

	[[ -n "$pickfiles" ]] && {
		dir=$(print $dir|
			awk '{s1=index($0,"("); print substr($0,1,s1-1);}');
	}

	cd $PROJECT_PREFIX/$project_name/$dir 2>/dev/null || {
		logwarn "Directory \"$dir\" does not exist - ignoring.";
		continue;
	}

	#################################################################
	# Because of the extended attribute the "DIR:" might be used	#
	# multiple times for the same directory - if so, only repear	#
	# the "directory" line if similar lines are grouped.		#
	#################################################################

	[[ ! -d "$oodir/$destdir" ]] && {
		mkdir -m 755 -p "$oodir/$destdir" || {
			logerr "Unable to create directory." 18;
		} ;
	}

	#################################################################
	# Now dump all the files in this directory...			#
	#################################################################

	for cfile in $(eval ls -d "$pattern" 2>/dev/null)
	do
		#########################################################
		# Ignore "ignore files...				#
		#########################################################

		myext="$(print $cfile|awk -v FS="." 'NF>1 {print $NF}')"
		[[ "$myext" = "ignore" ]] && continue

		if [[ -f "$cfile.ignore" ]]
		then
			logmsg "Excluding \"$dir/$cfile\" from package."
			continue
		fi
		
		[[ ! -f $cfile ]] && continue
		#################################################
		# Here we check to see if the suffix matches	#
		# one of those in the pkg_ignore_suffixes list.	#
		#################################################

		if [[ -n "$pkg_ignore_suffixes" ]]
		then
			myignore=0
			mysuff=".${cfile##*.}"
			for suffix in $pkg_ignore_suffixes
			do
				if [[ "$suffix" = "$mysuff" ]]
				then
					myignore=1
					break
				fi
			done
			if [[ $myignore -eq 1 ]]
			then
				logmsg "Excluding \"$dir/$cfile\" from package build."
				continue
			fi
		fi
		#################################################
		# Copy the file to the package directory...	#
		#################################################
		cp $PROJECT_PREFIX/$project_name/$dir/$cfile "$oodir/$destdir" || {
			logerr "Unable to copy directory" 7;
		}
		#################################################
		# owner, group and perms are also set - but as	#
		# part of the post install...			#
		#################################################
		print "chmod $perms $destdir/$cfile" >>$permsfile
		print "chown $user:$group $destdir/$cfile" >>$permsfile
	done
	cd $mycd
done

#########################################################################
# slackware packages can only deal with a post install, so ignore	#
# anything else configured.						#
#########################################################################

pkg_postinstall=$(loadvar $PROJECT_PREFIX/$project_name POSTINSTALL|awk '{print $2}')

[[ ! -d $oodir/install ]] && {
	mkdir $oodir/install || {
		logerr "Unable to create install directory!" 15;
	} ;
}

print "$slack_desc" >$oodir/install/slack-desc
#########################################################################
# If a post installation script was specified and exists, then it 	#
# is copied into the install directory and renamed to doinst.sh.	#
#########################################################################

print "#/bin/sh" >$oodir/install/doinst.sh
if [[ -f "$permsfile" ]]
then
	cat $permsfile >>$oodir/install/doinst.sh || {
		logerr "Unable to copy post install script!" 16;
	}
fi

if [[ -n "$pkg_postinstall" && -f "$PROJECT_PREFIX/$project_name/$pkg_postinstall" ]]
then
	cat "$PROJECT_PREFIX/$project_name/$pkg_postinstall" >>$oodir/install/doinst.sh || {
		logerr "Unable to copy post install script!" 16;
	}
fi

if [[ -f $oodir/install/doinst.sh ]]
then
	chmod 755 $oodir/install/doinst.sh || {
		logerr "Unable to set execute permissions on doinst.sh script." 17;
	}
fi

mycd=$PWD
cd $oodir || logerr "Unable to change directory." 18

tar czf $pkg_depot/$pkgfile_name . || logerr "Unable to create package." 19

exit 0
